﻿#include "Skeleton.h"
#include "Common.h"
#include <string>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "GlmUtil.h"

namespace DYGraphics
{
	Skeleton::Skeleton(): mRootBone(nullptr), mBoneArray(nullptr), mBoneCount(0) { }

	Skeleton::~Skeleton()
	{
		if (mBoneArray != nullptr)
		{
			for (int i = 0; i < mBoneCount; i++)
			{
				delete mBoneArray[i];
			}
			delete[] mBoneArray;
		}

		mRootBone = nullptr;
		mBoneArray = nullptr;
		mBoneMap.clear();
	}

	void Skeleton::SetBone(int pIndex, Bone* pBone)
	{
		std::string boneName = pBone->GetName();
		if (mBoneMap.count(boneName) > 0)
		{
			printf("Skeleton::AddBone already has bone: %s \n", boneName.c_str());
			return;
		}

		pBone->SetIndex(pIndex);
		mBoneArray[pIndex] = pBone;
		mBoneMap[boneName] = pBone;
	}

	Bone* Skeleton::GetBone(unsigned int idx) const
	{
		if (idx >= mBoneCount)
		{
			printf("Skeleton::GetBone invalid bone index: %d \n", idx);
			return nullptr;
		}

		return mBoneArray[idx];
	}

	Bone* Skeleton::GetBone(std::string name) const
	{
		auto iter = mBoneMap.find(name);
		if (iter != mBoneMap.end())
		{
			return iter->second;
		}

		printf("Skeleton::GetBone invalid bone name: %s \n", name.c_str());
		return nullptr;
	}

	void Skeleton::AppyAnimFrame(AnimationFrame* frames)
	{
		// 设置所有骨骼在当前Pose下的局部矩阵
		for (int i = 0; i < frames->mFrames.size(); i++)
		{
			AnimationBoneFrame frame = frames->mFrames[i];
			std::string boneName = frame.mBoneName;
			Bone* bone = GetBone(boneName);
			//bone->mLclMat = glm::MatrixTRS(frame.mTranslation, frame.mRotation, frame.mScaling);
			bone->mLclMat = glm::MatrixTRS(frame.mTranslation, frame.mRotation, glm::vec3(1.0f, 1.0f, 1.0f));
		}

		// 求值全局矩阵，从当前骨骼迭代的根骨骼
		int boneCnt = GetBoneCount();
		for (int i = 0; i < boneCnt; i++)
		{
			Bone* bone = GetBone(i);
			glm::mat4 globalMat = bone->mLclMat;
			Bone* temp = bone->GetParent();
			while (temp != nullptr)
			{
				globalMat = temp->mLclMat * globalMat;
				temp = temp->GetParent();
			}
			bone->mGlobalMat = globalMat;
		}
	}
}
